﻿using Abp;
using Abp.Configuration.Startup;
using Abp.Data;
using Abp.Domain.Uow;
using Abp.EntityFrameworkCore;
using Abp.Extensions;
using Abp.MultiTenancy;
using Abp.Zero.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using System;
using System.Net.Sockets;
using System.Threading;
using System.Transactions;

namespace AbpProjectTemplate.EntityFrameworkCore
{
    public class AppZeroDbMigrator : AbpZeroDbMigrator<AppDbContext>
    {
        private readonly IUnitOfWorkManager _unitOfWorkManager;
        private readonly IDbPerTenantConnectionStringResolver _connectionStringResolver;
        private readonly IDbContextResolver _dbContextResolver;

        public AppZeroDbMigrator(
            IUnitOfWorkManager unitOfWorkManager,
            IDbPerTenantConnectionStringResolver connectionStringResolver,
            IDbContextResolver dbContextResolver)
            : base(
                unitOfWorkManager,
                connectionStringResolver,
                dbContextResolver)
        {
            this._unitOfWorkManager = unitOfWorkManager;
            this._connectionStringResolver = connectionStringResolver;
            this._dbContextResolver = dbContextResolver;
        }

        bool CheckServer(string ip, int port)
        {
            try
            {
                TcpClient tcpClient = new TcpClient();
                tcpClient.Connect(ip, port);//对远程计算机的指定端口提出TCP连接请求
                return true;
            }
            catch {
                //Console.WriteLine(ex.Message);
                return false;
            }
        }

        protected override void CreateOrMigrate(AbpTenantBase tenant, Action<AppDbContext> seedAction)
        {
            var args = new DbPerTenantConnectionStringResolveArgs(
                tenant == null ? (int?)null : (int?)tenant.Id,
                tenant == null ? MultiTenancySides.Host : MultiTenancySides.Tenant
            );

            args["DbContextType"] = typeof(AppDbContext);
            args["DbContextConcreteType"] = typeof(AppDbContext);

            var nameOrConnectionString = ConnectionStringHelper.GetConnectionString(
                this._connectionStringResolver.GetNameOrConnectionString(args)
            );

            using (var uow = this._unitOfWorkManager.Begin(TransactionScopeOption.Suppress))
            {
                using (var dbContext = this._dbContextResolver.Resolve<AppDbContext>(nameOrConnectionString, null))
                {
                    var db = dbContext.Database.GetDbConnection();
                    var port = 1433;
                    var dataSourceItems = db.DataSource.Split(',');
                    var ip = dataSourceItems[0];
                    if (dataSourceItems.Length > 1)
                        port = dataSourceItems[1].To<int>();
                    //while (!this.CheckServer(ip, port))
                    //{
                    //    Console.WriteLine("waiting for database ..");
                    //    Thread.Sleep(5000);
                    //}
                    dbContext.Database.Migrate();
                    seedAction?.Invoke(dbContext);
                    this._unitOfWorkManager.Current.SaveChanges();
                    uow.Complete();
                }
            }
        }
    }
}

